package com.imyuanma.qingyun.fs.controller;

import com.imyuanma.qingyun.common.exception.BaseException;
import com.imyuanma.qingyun.common.model.response.Result;
import com.imyuanma.qingyun.common.util.CollectionUtil;
import com.imyuanma.qingyun.common.util.StringUtil;
import com.imyuanma.qingyun.common.util.WebUtil;
import com.imyuanma.qingyun.common.util.io.FileDownloadUtil;
import com.imyuanma.qingyun.fs.configuration.FsBaseConfiguration;
import com.imyuanma.qingyun.fs.model.FsFile;
import com.imyuanma.qingyun.fs.model.enums.EFsMediaType;
import com.imyuanma.qingyun.fs.service.IFsFileService;
import com.imyuanma.qingyun.fs.service.IFsFileStreamService;
import com.imyuanma.qingyun.fs.util.FsBusinessUtil;
import com.imyuanma.qingyun.fs.util.ImageUtil;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件流网关
 *
 * @author wangjy
 * @date 2022/07/24 00:14:11
 */
@Controller
@RequestMapping(value = "/fs/file", method = {RequestMethod.GET, RequestMethod.POST})
public class FsFileStreamController {

    private static final Logger logger = LoggerFactory.getLogger(FsFileStreamController.class);

    @Autowired
    private IFsFileStreamService fileStreamService;

    @Autowired
    private IFsFileService fsFileService;

    @Autowired
    private FsBaseConfiguration fsBaseConfiguration;


    /**
     * 文件上传
     *
     * @param file
     * @param request
     * @return
     */
    @RequestMapping("/upload")
    @ResponseBody
    public Object upload(MultipartFile file, String folderId, String businessCode, HttpServletRequest request) {
        logger.info("[文件上传] 文件夹编号为：{},业务编号为: {}", folderId, businessCode);
        if (file != null && !file.isEmpty()) {
            FsFile fileInfo = fileStreamService.saveFile(file, folderId, businessCode);
            return Result.success(fileInfo);
        } else {
            return Result.error("文件不存在!");
        }
    }

    /**
     * 文件下载
     *
     * @param fileId
     * @param request
     * @throws Exception
     */
    @RequestMapping("/download")
    public void download(String fileId, HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("[文件下载] 待下载文件编号为:{}", fileId);
        FsFile fileInfo = fsFileService.get(fileId);
        if (fileInfo == null) {
            logger.warn("[下载文件] 文件[id={}]不存在:找不到对应的文件存根!", fileId);
            WebUtil.write2Response(response, "文件信息无效!");
            return;
        }
        File file = new File(fsBaseConfiguration.getRootDir() + fileInfo.getAddr());
        if (!file.exists()) {
            logger.warn("[下载文件] 文件[id={}]不存在:对应文件不存在,存储地址={}", fileId, fsBaseConfiguration.getRootDir() + fileInfo.getAddr());
            WebUtil.write2Response(response, "文件信息无效!");
            return;
        }
        String fileName = fileInfo.getName();
        // 文件下载类型
        response.setContentType("application/x-msdownload;");
        // 设置中文文件名
        FileDownloadUtil.setFileNameOfCN(request, response, fileName);
        // 设置内容长度
        response.setHeader("Content-Length", String.valueOf(file.length()));
        OutputStream os = response.getOutputStream();
        // 拷贝到输出流
        IOUtils.copy(new FileInputStream(file), os);
    }

    /**
     * 预览文件
     *
     * @param id       文件编号
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/preview/{id}")
    public void preview(@PathVariable("id") String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("[文件下载] 待预览文件编号为:{}", id);
        FsFile fileInfo = fsFileService.get(id);
        if (fileInfo == null) {
            logger.warn("[预览文件] 文件[id={}]不存在:找不到对应的文件存根!", id);
            WebUtil.write2Response(response, "文件信息无效!");
            return;
        }
        // 设置响应类型
        EFsMediaType mediaType = EFsMediaType.ofType(fileInfo.getMediaType());
        if (mediaType != null && mediaType.getContentType() != null) {
            response.setContentType(mediaType.getContentType());
        }
        // 设置文件名
        FileDownloadUtil.setInlineFileNameOfCN(request, response, fileInfo.getName());
        // 文件
        File file = new File(fsBaseConfiguration.getRootDir() + fileInfo.getAddr());
        if (!file.exists()) {
            logger.warn("[预览文件] 文件[id={}]不存在:对应文件不存在,存储地址={}", id, fsBaseConfiguration.getRootDir() + fileInfo.getAddr());
            WebUtil.write2Response(response, "文件信息无效!");
            return;
        }
        // 设置内容长度
        response.setHeader("Content-Length", String.valueOf(file.length()));
        OutputStream os = response.getOutputStream();
        // 拷贝到输出流
        IOUtils.copy(new FileInputStream(file), os);
    }

    /**
     * 删除文件
     *
     * @param fileId  文件编号
     * @param request
     * @return
     */
    @RequestMapping("/dropFile")
    @ResponseBody
    public Object dropFile(String fileId, HttpServletRequest request) {
        logger.info("[文件删除] 待删除文件编号为:{}", fileId);
        if (!fileStreamService.dropFile(fileId)) {
            return Result.error("文件删除失败!");
        }
        return Result.success();
    }

    /**
     * 删除文件夹
     *
     * @param folderId
     * @param request
     * @return
     */
    @RequestMapping("/dropFolder")
    @ResponseBody
    public Object dropFolder(String folderId, HttpServletRequest request) {
        logger.info("[文件夹删除] 待删除文件夹编号为:{}", folderId);
        if (!fileStreamService.dropFolder(folderId)) {
            return Result.error("文件夹删除失败!");
        }
        return Result.success();
    }

    /**
     * 创建文件夹
     *
     * @param folder
     * @param request
     * @return
     */
    @RequestMapping("/createFolder")
    @ResponseBody
    public Object createFolder(FsFile folder, HttpServletRequest request) {
        if (folder == null || folder.getName() == null || folder.getFolderId() == null) {
            return Result.error("新建文件夹失败:所属文件夹或文件夹名称为空!");
        } else {
            List<FsFile> list = new ArrayList<FsFile>();
            list.add(fileStreamService.createFolder(folder));
            return Result.success(list);
        }
    }

    /**
     * 获取图片流(restful形式)
     *
     * @param id
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/image/{id}")
    public void getImage2(@PathVariable("id") String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (StringUtil.isNotBlank(id)) {
            FsFile image = fsFileService.get(id);
            if (image != null) {
                // 图片文件
                File file = new File(fsBaseConfiguration.getRootDir() + image.getAddr());
                // 写文件响应
                ImageUtil.writeImageResponse(file, response);
            }
        }
    }

    /**
     * 获取指定规格的图片流(restful形式)
     *
     * @param id
     * @param level
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/image/{level}/{id}")
    public void getImage2(@PathVariable("id") String id, @PathVariable("level") String level, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (StringUtil.isNotBlank(id)) {
            FsFile image = fsFileService.get(id);
            if (image != null) {
                // 图片文件
                File file = null;
                if (StringUtil.isNotBlank(level)) {
                    String levelName = FsBusinessUtil.getLevelImageName(image.getAbsoluteAddr(), level);
                    file = new File(levelName);
                }
                if (file == null || !file.exists()) {
                    file = new File(image.getAbsoluteAddr());
                }
                // 写文件响应
                ImageUtil.writeImageResponse(file, response);
            }
        }
    }


    /**
     * 文件传输(接收端)
     *
     * @param folderId 指定存储文件夹编号,默认为根目录
     * @param request
     * @return
     */
    @RequestMapping("/transferFile")
    @ResponseBody
    public Object transferFile(String folderId, String businessCode, DefaultMultipartHttpServletRequest request) {
        List<MultipartFile> list = WebUtil.getMultipartFileFromRequest(request);
        if (CollectionUtil.isEmpty(list)) {
            return Result.error("文件不存在!");
        }
        // 批量保存文件
        try {
            List<FsFile> fsList = fileStreamService.saveFiles(list, folderId, businessCode);
            return Result.success(fsList);
        } catch (BaseException e) {//对于业务异常,做相关处理,给调用端提供详细错误信息
            logger.error("[文件传输] 文件保存异常", e);
            return Result.error(e.getInfo());
        }
    }

}
